#pragma once

#include <atomic>
#include <mutex>
#include <string>
#include <vector>
#include <memory>
#include <cassert>
#include <stdarg.h>
#include <functional>
#include <unordered_map>
#include "format.hpp"
#include "loglevel.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "asyncloop.hpp"
/*  日志类：整合日志等级、消息、格式化消息、落地消息
    抽象基类派生出同步和异步落地方式
    抽象类的接口:Debug\info\error\warnig\fatal\ log实际输出接口
        具体的子类,往哪里落地
*/

namespace ns_logger
{
    class Logger;
    using LoggerPtr = std::shared_ptr<Logger>;
    class Logger
    {
    public:
        Logger(const std::string &logger_name, LogLevel::value level,
               const FormatterPtr &format, std::vector<LogSinkPtr> sinks)
            : _logger_name(logger_name), _format(format), _limit_level(level), _sinks(sinks.begin(), sinks.end())
        {
        }

        virtual void Debug(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::value::Dubug < _limit_level)
                return;
            // 展开可变参数
            char *ret;
            va_list lt;
            va_start(lt, fmt);
            int len = vasprintf(&ret, fmt, lt);
            if (len == -1)
            {
                std::cout << "可变参数解析失败!" << std::endl;
                return;
            }
            va_end(lt);
            // std::cout << "组织的消息是" << std::endl;
            //  组织成一条消息
            serialize(LogLevel::value::Dubug, file, line, ret);
            free(ret);
        }
        virtual void Info(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::value::Info < _limit_level)
                return;
            char *ret;
            va_list lt;
            va_start(lt, fmt);
            int len = vasprintf(&ret, fmt, lt);
            if (len == -1)
            {
                std::cout << "可变参数解析失败!" << std::endl;
                return;
            }
            va_end(lt);
            // 组织成一条消息
            serialize(LogLevel::value::Info, file, line, ret);
            free(ret);
        }
        virtual void Warning(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::value::Warning < _limit_level)
                return;
            char *ret;
            va_list lt;
            va_start(lt, fmt);
            int len = vasprintf(&ret, fmt, lt);
            if (len == -1)
            {
                std::cout << "可变参数解析失败!" << std::endl;
                return;
            }
            va_end(lt);
            // 组织成一条消息
            serialize(LogLevel::value::Warning, file, line, ret);
            free(ret);
        }
        virtual void Error(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::value::Error < _limit_level)
                return;
            char *ret;
            va_list lt;
            va_start(lt, fmt);
            int len = vasprintf(&ret, fmt, lt);
            if (len == -1)
            {
                std::cout << "可变参数解析失败!" << std::endl;
                return;
            }
            va_end(lt);
            // 组织成一条消息
            serialize(LogLevel::value::Error, file, line, ret);
            free(ret);
        }
        virtual void Fatal(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::value::Fatal < _limit_level)
                return;
            char *ret;
            va_list lt;
            va_start(lt, fmt);
            int len = vasprintf(&ret, fmt, lt);
            if (len == -1)
            {
                std::cout << "可变参数解析失败!" << std::endl;
                return;
            }
            va_end(lt);
            // 组织成一条消息
            // std::cout << "组织的消息是:" << ret << std::endl;
            serialize(LogLevel::value::Fatal, file, line, ret);
            free(ret);
        }

    protected:
        virtual void log(const char *data, size_t len) = 0;
        void serialize(LogLevel::value level, const std::string &file, size_t line, const char *data)
        {
            LogMsg lg(level, file, line, _logger_name, data);
            // 数据格式化,并放到流中
            std::stringstream ss;
            _format->format(ss, lg);
            log(ss.str().c_str(), ss.str().size());
        }

    protected:
        std::mutex _mutex;
        std::atomic<LogLevel::value> _limit_level;
        std::string _logger_name;
        std::vector<LogSinkPtr> _sinks; // 可能存在多种落地方式
        FormatterPtr _format;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::value level,
                   const FormatterPtr &formate, std::vector<LogSinkPtr> sinks)
            : Logger(logger_name, level, formate, sinks)
        {
        }
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };
    enum class LogType
    {
        SYNC = 0,
        ASYNC
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, LogLevel::value level,
                    const FormatterPtr &formate, std::vector<LogSinkPtr> sinks, AsyncSafeType safe_type)
            : Logger(logger_name, level, formate, sinks)
        {
            _pasync = std::make_shared<AsyncLoop>(std::bind(&AsyncLogger::func, this, std::placeholders::_1), safe_type);
            // std::cout << "构建异步工作器成功!" << std::endl;
        }
        void log(const char *data, size_t len)
        {
            // std::unique_lock<std::mutex> lock(_mutex); push是线程安全的
            // 写数据往缓冲区放数据即可
            // std::cout << "buffer log的数据是:" << data << std::endl;
            _pasync->Push(data, len);
        }

    private:
        void func(Buffer &buffer)
        {
            if (buffer.Empty())
                return;
            // 遍历所有的落地方式
            for (auto &sink : _sinks)
            {
                // std::cout<<"func的数据是:"<<buffer.GetFront()<<std::endl;
                sink->log(buffer.GetFront(), buffer.Readable());
            }
        }

    private:
        AsyncLoopPtr _pasync;
    };

    // 建造者模式
    // 抽象接口类
    // 派生出具体的接口类
    class LoggerBuilde
    {
    public:
        LoggerBuilde()
            : _type(LogType::SYNC), _limit_level(LogLevel::value::Dubug), _safe_type(AsyncSafeType::Async_Safe)
        {
        }
        void BuildType(LogType type) { _type = type; }
        void BuildName(std::string log_name) { _log_name = log_name; }
        void EnableUnSafe() { _safe_type = AsyncSafeType::Async_Unsafe; }
        void BuildLimit(LogLevel::value limit_level) { _limit_level = limit_level; }
        void BuildFormat(const std::string &foamat) { _formatter = std::make_shared<Formatter>(foamat); }
        template <typename SinkType, typename... Args>
        void BuildSink(Args &&...args)
        {
            LogSinkPtr psink = SinkFoctory::CreateSink<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual LoggerPtr build() = 0;

    protected:
        AsyncSafeType _safe_type;
        LogType _type;
        std::string _log_name;
        LogLevel::value _limit_level;
        FormatterPtr _formatter;
        std::vector<LogSinkPtr> _sinks;
    };

    class LogcalLoggerBuilde : public LoggerBuilde
    {
    public:
        LoggerPtr build() override
        {
            assert(!_log_name.empty());
            if (!_formatter.get())
                _formatter = std::make_shared<Formatter>();
            if (_sinks.empty())
                _sinks.push_back(SinkFoctory::CreateSink<StdoutSink>());
            if (_type == LogType::ASYNC)
                return std::make_shared<AsyncLogger>(_log_name, _limit_level, _formatter, _sinks, _safe_type);
            return std::make_shared<SyncLogger>(_log_name, _limit_level, _formatter, _sinks);
        }
    };

    /*
        全局的单例日志器管理类
        生成一个默认的root器，管理全局的日志器
    */

    class LoggerManager
    {
    private:
        LoggerManager()
        {
            // 创建root
            std::unique_ptr<LogcalLoggerBuilde> localbuild(new LogcalLoggerBuilde());
            localbuild->BuildName("root");
            _root_logger = localbuild->build();
            AddLogger("root", _root_logger);
        }
        ~LoggerManager() {}
        LoggerManager &operator=(const LoggerManager &) = delete;
        LoggerManager(const LoggerManager &) = delete;

    public:
        // 单例模式
        static LoggerManager &GetInstance()
        {
            static LoggerManager _eton;
            // 返回单例
            // std::cout << "创建单例" << std::endl;
            return _eton;
        }
        bool IsExistsLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_loggers.count(name))
                return true;
            return false;
        }

        void AddLogger(const std::string &name, const LoggerPtr &loggerptr)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_loggers.count(name))
                return;
            // std::cout << "添加日志器" << std::endl;
            _loggers.insert(std::make_pair(name, loggerptr));
        }
        LoggerPtr GetRootLogger()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _root_logger;
        }

        LoggerPtr GetLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_loggers.count(name))
                return _loggers[name];
            return LoggerPtr();
        }

    private:
        LoggerPtr _root_logger;
        std::unordered_map<std::string, LoggerPtr> _loggers;
        std::mutex _mutex;
    };

    // 构建全局的建造者
    // 多了一步，把日志器添加进单例
    class GlobalLoggerBuilder : public LoggerBuilde
    {
    public:
        LoggerPtr build() override
        {
            assert(!_log_name.empty());
            if (!_formatter.get())
                _formatter = std::make_shared<Formatter>();
            if (_sinks.empty())
                _sinks.push_back(SinkFoctory::CreateSink<StdoutSink>());
            LoggerPtr lp;
            if (_type == LogType::ASYNC)
                lp = std::make_shared<AsyncLogger>(_log_name, _limit_level, _formatter, _sinks, _safe_type);
            else
                lp = std::make_shared<SyncLogger>(_log_name, _limit_level, _formatter, _sinks);
            LoggerManager::GetInstance().AddLogger(_log_name, lp);
            // std::cout << "全局日志器构建完成" << std::endl;
            return lp;
        }
    };
}